package io.gitee.mingbaobaba.security.core.service;

import io.gitee.mingbaobaba.security.core.constants.ErrorCodeConstant;
import io.gitee.mingbaobaba.security.core.constants.SecurityConstant;
import io.gitee.mingbaobaba.security.core.convert.SecurityLoginParamsConvertSession;
import io.gitee.mingbaobaba.security.core.convert.SecurityLoginParamsConvertToken;
import io.gitee.mingbaobaba.security.core.domain.SecurityLoginParams;
import io.gitee.mingbaobaba.security.core.domain.SecurityPagination;
import io.gitee.mingbaobaba.security.core.domain.SecuritySession;
import io.gitee.mingbaobaba.security.core.domain.SecurityToken;
import io.gitee.mingbaobaba.security.core.enums.SecurityConditionType;
import io.gitee.mingbaobaba.security.core.exception.SecurityBaseException;
import io.gitee.mingbaobaba.security.core.exception.SecurityBusinessException;
import io.gitee.mingbaobaba.security.core.exception.SecurityUnLoginException;
import io.gitee.mingbaobaba.security.core.factory.SecurityFactory;
import io.gitee.mingbaobaba.security.core.function.IdentitySwitchFunction;
import io.gitee.mingbaobaba.security.core.listener.SecurityEventPublishManager;
import io.gitee.mingbaobaba.security.core.properties.SecurityProperties;
import io.gitee.mingbaobaba.security.core.request.SecurityRequest;
import io.gitee.mingbaobaba.security.core.response.SecurityResponse;
import io.gitee.mingbaobaba.security.core.utils.CommonUtil;
import io.gitee.mingbaobaba.security.core.utils.DateUtil;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>认证接口实现</p>
 *
 * @author yingsheng.ye
 * @version 1.0.0
 * @since 2023/8/21 22:09
 */
public class SecurityServiceImpl implements SecurityService {

    /**
     * 登录操作
     *
     * @param loginId 登录Id
     * @param model   登录参数
     */
    @Override
    public void doLogin(String loginId, SecurityLoginParams model) {
        //检查并设置SecuritySession信息
        SecuritySession currentSession = checkAndSetSecuritySession(loginId, model);
        //持久化保存session
        currentSession.flushSessionStorage();
        //持久化保存token
        currentSession.getCurrentSecurityToken().flushTokenStorage();
        //存储token到request参数中
        setRequestInfo(currentSession);
        //将参数设置响应response中
        setResponseInfo(currentSession);
        //发布登录操作事件
        SecurityEventPublishManager.doLogin(loginId, currentSession.getCurrentSecurityToken().getToken(), model);
    }

    /**
     * 创建指定账号的登录信息
     *
     * @param loginId    登录Id
     * @param loginModel 登录参数
     * @return 登录token
     */
    @Override
    public String createLoginByLoginId(String loginId, SecurityLoginParams loginModel) {
        SecuritySession currentSession = getCurrentSecuritySession();
        if (currentSession.getLoginId().equals(loginId)) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_INVALID_PARAMS,
                    "创建指定账号的登录Id不能与当前登录Id相同");
        }
        //检查并设置SecuritySession信息
        SecuritySession session = checkAndSetSecuritySession(loginId, loginModel);
        //持久化保存session
        session.flushSessionStorage();
        //持久化保存token
        currentSession.getCurrentSecurityToken().flushTokenStorage();
        return session.getCurrentSecurityToken().getToken();
    }

    /**
     * 根据token获取SecuritySession信息
     *
     * @param token 用户token
     * @return SecuritySession
     */
    @Override
    public SecuritySession getSecuritySessionByToken(String token) {
        SecurityToken securityToken = SecurityFactory.getSecurityRepository.get().getSecurityTokenByTokenValue(token);
        if (Objects.isNull(securityToken) || StringUtils.isBlank(securityToken.getLoginId())) {
            return null;
        }
        SecuritySession securitySession = getSecuritySessionByLoginId(securityToken.getLoginId());
        if (Objects.isNull(securitySession)) {
            return null;
        }
        //设置当前的token信息
        securitySession.setCurrentSecurityToken(securityToken);
        return securitySession;
    }

    /**
     * 根据loginId获取SecuritySession信息
     *
     * @param loginId 用户登录Id
     * @return SecuritySession
     */
    @Override
    public SecuritySession getSecuritySessionByLoginId(String loginId) {
        return SecurityFactory.getSecurityRepository.get().getSecuritySessionByLoginId(loginId);
    }

    /**
     * 获取当前SecuritySession信息
     *
     * @return SecuritySession
     */
    @Override
    public SecuritySession getCurrentSecuritySession() {
        //优先内部设置自定义参数获取，仅框架内部传参使用
        String token = (String) SecurityFactory.getSecurityRequest.get()
                .getAttribute(SecurityConstant.SECURITY_CUSTOM_IDENTITY_TOKEN);

        if (StringUtils.isBlank(token)) {
            //尝试从请求参数中获取
            token = (String) SecurityFactory.getSecurityRequest.get()
                    .getAttribute(SecurityFactory.getConfig.get().getSecurityName());
        }

        if (StringUtils.isBlank(token)) {
            //尝试从header头中获取
            token = SecurityFactory.getSecurityRequest.get()
                    .getHeader(SecurityFactory.getConfig.get().getSecurityName());
        }

        if (StringUtils.isBlank(token)) {
            //尝试从cookie中读取
            SecurityProperties.CookieProperties cookieProperties = SecurityFactory.getConfig.get().getCookieConfig();
            token = SecurityFactory.getSecurityRequest.get().getCookie(cookieProperties.getCookieName());
        }

        //都没有拿到则认为没有认证登录
        if (StringUtils.isBlank(token)) {
            throw new SecurityUnLoginException(ErrorCodeConstant.CODE_INVALID_TOKEN, "未登录认证");
        }

        token = CommonUtil.cutPrefixToken.apply(token);
        SecuritySession securitySession = getSecuritySessionByToken(token);
        if (Objects.isNull(securitySession) || Objects.isNull(securitySession.getCurrentSecurityToken())) {
            throw new SecurityUnLoginException(ErrorCodeConstant.CODE_INVALID_SESSION, "无效的认证信息");
        }
        return securitySession;
    }

    /**
     * 检查当前登录的token信息
     * 调用此方法会自动调用续约
     */
    @Override
    public void checkToken() {
        SecuritySession session = getCurrentSecuritySession();

        if (Objects.isNull(session) || Objects.isNull(session.getCurrentSecurityToken())) {
            throw new SecurityUnLoginException(ErrorCodeConstant.CODE_INVALID_TOKEN, "当前token已失效");
        }

        if (SecurityConstant.TOKEN_STATE_KICKED_OFFLINE.equals(session.getCurrentSecurityToken().getState())) {
            throw new SecurityUnLoginException(ErrorCodeConstant.CODE_KICKED_TOKEN, "当前token已被踢下线");
        }

        if (SecurityConstant.TOKEN_STATE_REPLACE_OFFLINE.equals(session.getCurrentSecurityToken().getState())) {
            throw new SecurityUnLoginException(ErrorCodeConstant.CODE_KNOCKED_TOKEN, "当前token已被顶下线");
        }

        if (SecurityConstant.TOKEN_STATE_BANNED.equals(session.getCurrentSecurityToken().getState())) {
            throw new SecurityUnLoginException(ErrorCodeConstant.CODE_BANNED_TOKEN, "当前token已被封禁");
        }

        //判断token续约操作
        SecurityToken securityToken = session.getCurrentSecurityToken();
        if (!SecurityConstant.NON_EXPIRING.equals(securityToken.getActivityTimeout())) {
            Long activityTimeout = tokenActivityTimeout(securityToken.getToken());
            if (null == activityTimeout || activityTimeout <= 0) {
                throw new SecurityUnLoginException(ErrorCodeConstant.CODE_TIMEOUT_TOKEN, "当前token已超时");
            }

            if (!Boolean.TRUE.equals(SecurityFactory.getConfig.get().getAutoRenewal())) {
                return;
            }

            //续约操作
            renewalToken(securityToken.getToken());
        }
    }

    /**
     * 检查指定的token信息
     *
     * @param token 指定的用户token
     */
    @Override
    public void checkToken(String token) {
        SecuritySession session = getSecuritySessionByToken(token);

        if (Objects.isNull(session) || Objects.isNull(session.getCurrentSecurityToken())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_INVALID_TOKEN, "指定token已失效");
        }

        if (SecurityConstant.TOKEN_STATE_KICKED_OFFLINE.equals(session.getCurrentSecurityToken().getState())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_KICKED_TOKEN, "指定token已被踢下线");
        }

        if (SecurityConstant.TOKEN_STATE_REPLACE_OFFLINE.equals(session.getCurrentSecurityToken().getState())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_KNOCKED_TOKEN, "指定token已被顶下线");
        }

        if (SecurityConstant.TOKEN_STATE_BANNED.equals(session.getCurrentSecurityToken().getState())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_BANNED_TOKEN, "指定token已被封禁");
        }
        SecurityToken securityToken = session.getCurrentSecurityToken();
        if (!SecurityConstant.NON_EXPIRING.equals(securityToken.getActivityTimeout())) {
            Long activityTimeout = tokenActivityTimeout(securityToken.getToken());
            if (null == activityTimeout || activityTimeout <= 0) {
                throw new SecurityBusinessException(ErrorCodeConstant.CODE_TIMEOUT_TOKEN, "指定token已超时");
            }
        }
    }

    /**
     * 踢下线操作
     */
    @Override
    public void kickOut() {
        kickOut(null);
    }

    /**
     * 踢下线操作
     *
     * @param token 用户token
     */
    @Override
    public void kickOut(String token) {
        SecuritySession session = StringUtils.isBlank(token) ? getCurrentSecuritySession() :
                getSecuritySessionByToken(token);
        if (Objects.isNull(session) || Objects.isNull(session.getCurrentSecurityToken())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_INVALID_TOKEN, "需要被踢下线的token无效");
        }
        SecurityToken securityToken = session.getCurrentSecurityToken();
        session.updateTokenInfoState(securityToken.getToken(), SecurityConstant.TOKEN_STATE_KICKED_OFFLINE);
        session.flushSessionStorage();
        SecurityEventPublishManager.doKickOut(session.getLoginId(), securityToken.getToken(),
                securityToken.getDeviceType());
    }

    /**
     * 顶下线操作
     */
    @Override
    public void replaceOut() {
        replaceOut(null);
    }

    /**
     * 顶下线操作
     *
     * @param token 用户token
     */
    @Override
    public void replaceOut(String token) {
        SecuritySession session = StringUtils.isBlank(token) ? getCurrentSecuritySession() :
                getSecuritySessionByToken(token);
        if (Objects.isNull(session) || Objects.isNull(session.getCurrentSecurityToken())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_INVALID_TOKEN, "需要被顶下线的token无效");
        }
        SecurityToken securityToken = session.getCurrentSecurityToken();
        session.updateTokenInfoState(securityToken.getToken(), SecurityConstant.TOKEN_STATE_REPLACE_OFFLINE);
        session.flushSessionStorage();
        SecurityEventPublishManager.doReplaceOut(session.getLoginId(), securityToken.getToken(),
                securityToken.getDeviceType());
    }

    /**
     * 续约token
     */
    @Override
    public void renewalToken() {
        renewalToken(null);
    }

    /**
     * 续签token
     *
     * @param token 用户token
     */
    @Override
    public void renewalToken(String token) {
        SecuritySession session = StringUtils.isBlank(token) ? getCurrentSecuritySession() :
                getSecuritySessionByToken(token);
        if (Objects.isNull(session) || Objects.isNull(session.getCurrentSecurityToken())) {
            return;
        }
        SecurityToken securityToken = session.getCurrentSecurityToken();
        //判断上次续约与本次的间隔
        Long autoRenewalIntervalTime = SecurityFactory.getConfig.get().getAutoRenewalIntervalTime();
        LocalDateTime activityTime = this.tokenLastActivityTime(securityToken.getToken());
        if (Objects.nonNull(activityTime) && activityTime.plusSeconds(autoRenewalIntervalTime).isBefore(LocalDateTime.now())) {
            session.renewalToken(securityToken.getToken());
            //续约成功通知
            SecurityEventPublishManager.doRenewal(session.getLoginId(), securityToken.getToken(),
                    securityToken.getDeviceType());
        }
    }

    /**
     * 封禁token
     */
    @Override
    public void bannedToken() {
        bannedToken(null);
    }

    /**
     * 封禁token
     *
     * @param token 用户token
     */
    @Override
    public void bannedToken(String token) {
        SecuritySession session = StringUtils.isBlank(token) ? getCurrentSecuritySession() :
                getSecuritySessionByToken(token);
        if (Objects.isNull(session) || Objects.isNull(session.getCurrentSecurityToken())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_INVALID_TOKEN, "需要被封禁的token无效");
        }
        SecurityToken securityToken = session.getCurrentSecurityToken();
        session.updateTokenInfoState(securityToken.getToken(), SecurityConstant.TOKEN_STATE_BANNED);
        session.flushSessionStorage();
        SecurityEventPublishManager.doBanned(session.getLoginId(), securityToken.getToken(),
                securityToken.getDeviceType());
    }

    /**
     * 解封token
     */
    @Override
    public void unsealToken() {
        unsealToken(null);
    }

    /**
     * 解封token
     *
     * @param token 用户token
     */
    @Override
    public void unsealToken(String token) {
        SecuritySession session = StringUtils.isBlank(token) ? getCurrentSecuritySession() :
                getSecuritySessionByToken(token);
        if (Objects.isNull(session) || Objects.isNull(session.getCurrentSecurityToken())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_INVALID_TOKEN, "需要被解封的token无效");
        }
        SecurityToken securityToken = session.getCurrentSecurityToken();
        session.updateTokenInfoState(securityToken.getToken(), SecurityConstant.TOKEN_STATE_NORMAL);
        session.flushSessionStorage();
        SecurityEventPublishManager.doUnseal(session.getLoginId(), securityToken.getToken(),
                securityToken.getDeviceType());
    }

    /**
     * 移除token
     *
     * @param token 用户token
     */
    @Override
    public void removeToken(String token) {
        SecuritySession session = getSecuritySessionByToken(token);
        if (Objects.isNull(session) || Objects.isNull(session.getCurrentSecurityToken())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_INVALID_TOKEN, "需要被删除的token无效");
        }
        SecurityToken securityToken = session.getCurrentSecurityToken();
        String deviceType = securityToken.getDeviceType();
        session.removeTokenInfo(securityToken.getToken());
        session.flushSessionStorage();
        if (SecurityFactory.getSecurityRepository.get().removeTokenByTokenValue(securityToken.getToken())) {
            //token被删除通知
            SecurityEventPublishManager.doRemove(session.getLoginId(), securityToken.getToken(), deviceType);
        }
    }

    /**
     * 退出操作
     */
    @Override
    public void loginOut() {
        loginOut(null);
    }

    /**
     * 退出操作
     *
     * @param token 用户token
     */
    @Override
    public void loginOut(String token) {
        SecuritySession session = StringUtils.isBlank(token) ? getCurrentSecuritySession() :
                getSecuritySessionByToken(token);
        if (Objects.isNull(session) || Objects.isNull(session.getCurrentSecurityToken())) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_INVALID_TOKEN, "需要被退出的token无效");
        }
        SecurityToken securityToken = session.getCurrentSecurityToken();
        String deviceType = securityToken.getDeviceType();
        session.removeTokenInfo(securityToken.getToken());
        //判断 token list 是否为空,如果为空则销毁此session
        if (session.getTokenInfoList().isEmpty()) {
            session.destroySecuritySession();
        } else {
            session.flushSessionStorage();
        }

        //清理request中的token信息
        SecurityFactory.getSecurityRequest.get().removeAttribute(SecurityFactory.getConfig.get().getSecurityName());

        //清理cookie
        if (Boolean.TRUE.equals(SecurityFactory.getConfig.get().getEnableCookie())) {
            SecurityProperties.CookieProperties cookieProperties = SecurityFactory.getConfig.get().getCookieConfig();
            SecurityFactory.getSecurityResponse.get()
                    .addCookie(cookieProperties.getCookieName(), null, 0)
                    .addCookie(SecurityConstant.SECURITY_SESSION_ID, null, 0);
        }

        if (SecurityFactory.getSecurityRepository.get().removeTokenByTokenValue(securityToken.getToken())) {
            SecurityEventPublishManager.doLoginOut(session.getLoginId(), securityToken.getToken(), deviceType);
        }
    }

    /**
     * 查询SecuritySession列表
     *
     * @param tokenValue token值，支持模糊匹配
     * @param page       当前页
     * @param limit      每页条数
     * @param sortedDesc 是否降序
     * @return SecurityPagination
     */
    @Override
    public SecurityPagination querySecuritySessionList(String tokenValue, Integer page, Integer limit, Boolean sortedDesc) {
        if (Objects.isNull(page) || page < 1) {
            page = 1;
        }
        if (Objects.isNull(limit)) {
            limit = 10;
        }
        SecurityPagination pagination = new SecurityPagination();
        List<String> list = SecurityFactory.getSecurityRepository.get().queryTokenList(tokenValue, sortedDesc);
        pagination.setTotal(Objects.isNull(list) ? 0L : list.size());
        List<SecuritySession> resultList = new ArrayList<>();
        if (Objects.nonNull(list)) {
            List<String> pageList = list.stream().skip((long) (page - 1) * limit)
                    .limit(limit).collect(Collectors.toList());
            //数据处理
            pageList.forEach(token -> {
                SecuritySession session = getSecuritySessionByToken(token);
                if (Objects.nonNull(session)) {
                    session.setTokenInfoList(null);
                } else {
                    session = new SecuritySession();
                    SecurityToken securityToken = new SecurityToken();
                    securityToken.setToken(token);
                    session.setCurrentSecurityToken(securityToken);
                }
                resultList.add(session);
            });
        }
        pagination.setRecords(resultList);
        return pagination;
    }

    /**
     * 查询token值列表
     *
     * @param tokenValue token值
     * @param sortedDesc 是否降序
     * @return List<String>
     */
    @Override
    public List<String> queryTokenValueList(String tokenValue, Boolean sortedDesc) {
        return SecurityFactory.getSecurityRepository.get().queryTokenList(tokenValue, sortedDesc);
    }

    /**
     * 获取session超时时间
     *
     * @param loginId 登录Id
     * @return 时长秒 -1表示永久有效
     */
    @Override
    public Long sessionTimeout(String loginId) {
        return SecurityFactory.getSecurityRepository.get().getSessionTimeoutByLoginId(loginId);
    }

    /**
     * 获取token超时时间
     *
     * @param token tokenValue
     * @return 时长秒 -1表示永久有效
     */
    @Override
    public Long tokenTimeout(String token) {
        return SecurityFactory.getSecurityRepository.get().getTokenTimeOutByTokenValue(token);
    }

    /**
     * 获取token活跃剩余时间
     *
     * @param token tokenValue
     * @return 时长秒 -1表示永久有效
     */
    @Override
    public Long tokenActivityTimeout(String token) {
        return SecurityFactory.getSecurityRepository.get().getTokenActivityTimeOutByTokenValue(token);
    }

    /**
     * 获取token的最新续约时间
     *
     * @param token tokenValue
     * @return 续约时间
     */
    @Override
    public LocalDateTime tokenLastActivityTime(String token) {
        String activityTime = SecurityFactory.getSecurityRepository.get().getActivityTimeByTokenValue(token);
        if (StringUtils.isBlank(activityTime)) {
            return null;
        }
        return DateUtil.strToLocalDateTime.apply(activityTime);
    }

    /**
     * 当前用户是否有指定角色
     *
     * @param roleCode 角色码
     * @return true 有 false 没有
     */
    @Override
    public Boolean hasRole(String roleCode) {
        return CommonUtil.hasRole.test(roleCode);
    }

    /**
     * 当前用户是否有指定角色
     *
     * @param roleCode      角色码
     * @param conditionType 条件
     * @return true 有 false 没有
     */
    @Override
    public Boolean hasRole(String[] roleCode, SecurityConditionType conditionType) {
        return CommonUtil.hasMultiPermValid(roleCode, conditionType, CommonUtil.hasRole);
    }

    /**
     * 当前用户是否有指定权限码
     *
     * @param permissionCode 权限码
     * @return true 有 false 没有
     */
    @Override
    public Boolean hasPermission(String permissionCode) {
        return CommonUtil.hasPermission.test(permissionCode);
    }

    /**
     * 当前用户是否有指定权限码
     *
     * @param permissionCode 权限码
     * @param conditionType  条件
     * @return true 有 false 没有
     */
    @Override
    public Boolean hasPermission(String[] permissionCode, SecurityConditionType conditionType) {
        return CommonUtil.hasMultiPermValid(permissionCode, conditionType, CommonUtil.hasPermission);
    }

    /**
     * 是否已登录
     *
     * @return true 登录 false 未登录
     */
    @Override
    public Boolean isLogin() {
        try {
            checkToken();
        } catch (SecurityBaseException e) {
            return false;
        }
        return true;
    }

    /**
     * 身份临时切换
     *
     * @param loginId            登录Id
     * @param identitySwitchFunc 执行函数
     */
    @Override
    public void identityTempSwitching(String loginId, IdentitySwitchFunction identitySwitchFunc) {
        SecurityRequest securityRequest = SecurityFactory.getSecurityRequest.get();
        //根据登录Id查询
        SecuritySession session = getSecuritySessionByLoginId(loginId);
        String token = null;
        if (Objects.nonNull(session)) {
            Optional<SecurityToken> optional = session.getTokenInfoList().stream().filter(item -> item.getState()
                    .equals(SecurityConstant.TOKEN_STATE_NORMAL)).findFirst();
            if (optional.isPresent()) {
                token = optional.get().getToken();
            }
        }
        if (StringUtils.isBlank(token)) {
            token = this.createLoginByLoginId(loginId, new SecurityLoginParams());
        }
        try {
            securityRequest.setAttribute(SecurityConstant.SECURITY_CUSTOM_IDENTITY_TOKEN, token);
            identitySwitchFunc.run();
        } finally {
            securityRequest.removeAttribute(SecurityConstant.SECURITY_CUSTOM_IDENTITY_TOKEN);
        }
    }

    /**
     * token数量统计
     *
     * @return 总数
     */
    @Override
    public Long getTokenCount() {
        List<String> list = SecurityFactory.getSecurityRepository.get().queryTokenList(null, true);
        if (Objects.isNull(list)) {
            return 0L;
        }
        return list.parallelStream().count();
    }

    /**
     * 设置请求信息
     *
     * @param securitySession SecuritySession
     */
    private void setRequestInfo(SecuritySession securitySession) {
        //清空全局存储的自定义token,防止登录时用户传入导致登录异常
        SecurityFactory.getSecurityRequest.get().removeAttribute(SecurityConstant.SECURITY_CUSTOM_IDENTITY_TOKEN);
        //将token设置到请求参数中
        SecurityFactory.getSecurityRequest.get().setAttribute(SecurityFactory.getConfig.get().getSecurityName(),
                CommonUtil.appendTokenPrefix.apply(securitySession.getCurrentSecurityToken().getToken()));
    }

    /**
     * 设置响应信息
     *
     * @param securitySession SecuritySession
     */
    private void setResponseInfo(SecuritySession securitySession) {
        //设置header
        SecurityFactory.getSecurityResponse.get().setHeader(SecurityFactory.getConfig.get().getSecurityName(),
                CommonUtil.appendTokenPrefix.apply(securitySession.getCurrentSecurityToken().getToken()));
        SecurityFactory.getSecurityResponse.get().addHeader(SecurityResponse.ACCESS_CONTROL_EXPOSE_HEADERS,
                SecurityFactory.getConfig.get().getSecurityName());

        //设置cookie
        if (Boolean.TRUE.equals(SecurityFactory.getConfig.get().getEnableCookie())) {
            SecurityProperties.CookieProperties cookieProperties = SecurityFactory.getConfig.get().getCookieConfig();
            SecurityFactory.getSecurityResponse.get()
                    //将 security token value 写入cookie
                    .addCookie(cookieProperties.getCookieName(), securitySession.getCurrentSecurityToken().getToken(),
                            securitySession.getCurrentSecurityToken().getTimeout().intValue())
                    //将 security session id 写入cookie
                    .addCookie(SecurityConstant.SECURITY_SESSION_ID, securitySession.getSecuritySessionId(),
                            securitySession.getCurrentSecurityToken().getTimeout().intValue());
        }
    }

    /**
     * 检查并设置登录信息
     *
     * @param loginId 登录id
     * @param model   登录参数
     * @return SecuritySession {@link SecuritySession}
     */
    private SecuritySession checkAndSetSecuritySession(String loginId, SecurityLoginParams model) {
        //判断是否超过最大颁发token数
        if (!SecurityConstant.NON_LIMIT.equals(SecurityFactory.getConfig.get().getIssueTokenMaxLimit())) {
            long tokenCount = this.getTokenCount();
            if (SecurityFactory.getConfig.get().getIssueTokenMaxLimit() >= tokenCount) {
                throw new SecurityBusinessException(ErrorCodeConstant.CODE_TOKEN_OVERTAKE_MAX_LIMIT,
                        "颁发token已超过最大限制数");
            }
        }
        SecurityToken securityToken = new SecurityLoginParamsConvertToken(loginId).convert(model);
        SecuritySession session = SecurityFactory.getSecurityRepository.get().getSecuritySessionByLoginId(loginId);
        if (Objects.isNull(session)) {
            session = new SecurityLoginParamsConvertSession(loginId, securityToken).convert(model);
            return session;
        }

        SecuritySession securitySession = session;
        if (!model.getMountData().isEmpty()) {
            securitySession.getMountData().putAll(model.getMountData());
        }
        securitySession.setCurrentSecurityToken(securityToken);

        List<SecurityToken> availableTokenInfoList = securitySession.getTokenInfoList()
                .stream().filter(item -> SecurityConstant.TOKEN_STATE_NORMAL.equals(item.getState()))
                .collect(Collectors.toList());
        if (!availableTokenInfoList.isEmpty()) {
            //最先登录的token
            SecurityToken earliestToken = availableTokenInfoList.get(0);
            //验证登录设备类型数量
            if (!SecurityConstant.NON_LIMIT.equals(SecurityFactory.getConfig.get().getMaxLoginDeviceTypeLimit())
                    && availableTokenInfoList.stream().map(SecurityToken::getDeviceType).distinct().count()
                    >= SecurityFactory.getConfig.get().getMaxLoginDeviceTypeLimit()
            ) {

                availableTokenInfoList.stream().filter(item -> item.getDeviceType()
                        .equals(earliestToken.getDeviceType())).forEach(tokenInfo -> {
                    //已达到登录设备类型上限，顶掉最先登录设备的所有相同的设备类型
                    securitySession.updateTokenInfoState(tokenInfo.getToken(), SecurityConstant.TOKEN_STATE_REPLACE_OFFLINE);
                    SecurityEventPublishManager.doReplaceOut(loginId, tokenInfo.getToken(), tokenInfo.getDeviceType());
                });
            }
            if (Boolean.TRUE.equals(SecurityFactory.getConfig.get().getIsConcurrentLogin())) {
                //允许并发，验证登录设备数量
                if (!SecurityConstant.NON_LIMIT.equals(SecurityFactory.getConfig.get().getMaxLoginLimit())
                        && availableTokenInfoList.size() >= SecurityFactory.getConfig.get().getMaxLoginLimit()) {
                    //已达到登录上限，顶掉最先登录的设备
                    securitySession.updateTokenInfoState(earliestToken.getToken(), SecurityConstant.TOKEN_STATE_REPLACE_OFFLINE);
                    SecurityEventPublishManager.doReplaceOut(loginId, earliestToken.getToken(), earliestToken.getDeviceType());
                }
            } else {
                //将旧的登录信息修改为被顶下线状态
                availableTokenInfoList.stream().filter(item -> item.getDeviceType().equals(securitySession.getCurrentSecurityToken().getDeviceType()))
                        .forEach(tokenInfo -> {
                            securitySession.updateTokenInfoState(tokenInfo.getToken(), SecurityConstant.TOKEN_STATE_REPLACE_OFFLINE);
                            SecurityEventPublishManager.doReplaceOut(securitySession.getLoginId(), tokenInfo.getToken(), tokenInfo.getDeviceType());
                        });
            }
        }

        securitySession.setUpdateTime(DateUtil.formatDateTime.apply(new Date()));
        securitySession.addTokenInfo(securitySession.getCurrentSecurityToken());
        return securitySession;
    }

}
